using System;
using System.Data;
using System.Data.Common;
using System.Collections.Generic;
using System.Text;
using System.Xml;

using DB = Pitoshka.DB;


namespace Pitoshka.DB
{
	public abstract class SqlEngine : IDisposable
	{
		#region Static Properties
		protected static string preferredConnString;
		public static string PreferredConnString 
		{
			get { return preferredConnString ; }
			set { preferredConnString  = value; }
		}
		#endregion

		#region Properties
		protected abstract DbConnection Connection { get; }
		protected string connectionString = null;
		protected int openedCount = 0;
		#endregion

		#region Constructors
		public SqlEngine() : this(PreferredConnString) { }
		public SqlEngine(string connectionString)
		{
			this.connectionString = connectionString;
		}
		#endregion

		#region ExecuteSelect methods
		public DataTable ExecuteSelect(string sql)
		{
			return ExecuteSelect(sql, CommandType.Text, new DB.DBParameter[0]);
		}
		public DataTable ExecuteSelect(string sql, CommandType commandType)
		{
			return ExecuteSelect(sql, commandType, new DB.DBParameter[0]);
		}
		public DataTable ExecuteSelect(string sql, CommandType commandType, DB.DBParameter parameter)
		{
			return ExecuteSelect(sql, commandType, new DB.DBParameter[1] { parameter });
		}
		public abstract DataTable ExecuteSelect(string sql, CommandType commandType, DB.DBParameter[] parameters);
		#endregion

		#region ExecuteDataSet methods
		public DataSet ExecuteDataSet(string sql)
		{
			return ExecuteDataSet(sql, CommandType.Text, new DB.DBParameter[0]);
		}
		public DataSet ExecuteDataSet(string sql, CommandType commandType)
		{
			return ExecuteDataSet(sql, commandType, new DB.DBParameter[0]);
		}
		public DataSet ExecuteDataSet(string sql, CommandType commandType, DB.DBParameter parameter)
		{
			return ExecuteDataSet(sql, commandType, new DB.DBParameter[1] { parameter });
		}
		public abstract DataSet ExecuteDataSet(string sql, CommandType commandType, DB.DBParameter[] parameters);
		#endregion

		#region ExecuteXML methods
		public XmlDocument ExecuteXML(string sql)
		{
			return ExecuteXML(sql, CommandType.Text, new DB.DBParameter[0]);
		}
		public XmlDocument ExecuteXML(string sql, CommandType commandType)
		{
			return ExecuteXML(sql, commandType, new DB.DBParameter[0]);
		}
		public XmlDocument ExecuteXML(string sql, CommandType commandType, DB.DBParameter parameter)
		{
			return ExecuteXML(sql, commandType, new DB.DBParameter[1] { parameter });
		}
		public abstract XmlDocument ExecuteXML(string sql, CommandType commandType, DB.DBParameter[] parameters);
		#endregion

		#region ExecuteXMLreader methods
		public XmlReader ExecuteXMLreader(string sql)
		{
			return ExecuteXMLreader(sql, CommandType.Text, new DB.DBParameter[0]);
		}
		public XmlReader ExecuteXMLreader(string sql, CommandType commandType)
		{
			return ExecuteXMLreader(sql, commandType, new DB.DBParameter[0]);
		}
		public XmlReader ExecuteXMLreader(string sql, CommandType commandType, DB.DBParameter parameter)
		{
			return ExecuteXMLreader(sql, commandType, new DB.DBParameter[1] { parameter });
		}
		public abstract XmlReader ExecuteXMLreader(string sql, CommandType commandType, DB.DBParameter[] parameters);
		#endregion

		#region ExecuteNonQuery methods
		public int ExecuteNonQuery(string sql)
		{
			return ExecuteNonQuery(sql, CommandType.Text, new DB.DBParameter[0]);
		}
		public int ExecuteNonQuery(string sql, CommandType commandType)
		{
			return ExecuteNonQuery(sql, commandType, new DB.DBParameter[0]);
		}
		public int ExecuteNonQuery(string sql, CommandType commandType, DB.DBParameter parameter)
		{
			return ExecuteNonQuery(sql, commandType, new DB.DBParameter[] { parameter });
		}
		public abstract int ExecuteNonQuery(string sql, CommandType commandType, DB.DBParameter[] parameters);
		#endregion

		#region ExecuteScalar methods
		public object ExecuteScalar(string sql)
		{
			return ExecuteScalar(sql, CommandType.Text, new DB.DBParameter[0]);
		}
		public object ExecuteScalar(string sql, CommandType commandType)
		{
			return ExecuteScalar(sql, commandType, new DB.DBParameter[0]);
		}
		public object ExecuteScalar(string sql, CommandType commandType, DB.DBParameter parameter)
		{
			return ExecuteScalar(sql, commandType, new DB.DBParameter[] { parameter });
		}
		public abstract object ExecuteScalar(string sql, CommandType commandType, DB.DBParameter[] parameters);
		#endregion

		#region ExecuteReader methods
		public DbDataReader ExecuteReader(string sql)
		{
			return ExecuteReader(sql, CommandType.Text, new DB.DBParameter[0]);
		}
		public DbDataReader ExecuteReader(string sql, CommandType commandType)
		{
			return ExecuteReader(sql, commandType, new DB.DBParameter[0]);
		}
		public DbDataReader ExecuteReader(string sql, CommandType commandType, DB.DBParameter parameter)
		{
			return ExecuteReader(sql, commandType, new DB.DBParameter[] { parameter });
		}
		public abstract DbDataReader ExecuteReader(string sql, CommandType commandType, DB.DBParameter[] parameters);
		#endregion

		#region CreateDbCommand methods
		public DbCommand CreateDbCommand(string sql)
		{
			return CreateDbCommand(sql, CommandType.Text);
		}
		public DbCommand CreateDbCommand(string sql, CommandType commandType)
		{
			return CreateDbCommand(sql, CommandType.Text, new DB.DBParameter[0]);
		}
		public DbCommand CreateDbCommand(string sql, CommandType commandType, DBParameter[] parameters)
		{
			throw new Exception("The method or operation is not implemented.");
		}
		#endregion

		#region Open/Close SqlConnection
		public void OpenConnection()
		{
			if (Connection.State == System.Data.ConnectionState.Closed)
			{
				Connection.Open();
				this.openedCount = 1;
			}
			else
				this.openedCount++;
		}
		public void CloseConnection()
		{
			if (Connection.State == System.Data.ConnectionState.Closed)
				return;
			if (this.openedCount < 2)
			{
				this.openedCount = 1;
				Connection.Close();
			}
			else
				this.openedCount--;
		}
		public void ForceCloseConnection()
		{
			if (Connection.State == System.Data.ConnectionState.Closed)
				return;
			this.openedCount = 1;
			Connection.Close();
		}
		#endregion

		#region IDisposable Members
		public void Dispose()
		{
			this.ForceCloseConnection();
		}
		#endregion
	}
}
